package com.mamingchao.basic.generic_type;

import com.mamingchao.basic.ExtendVsInterface.Song;

import java.util.ArrayList;
import java.util.List;

/**
 * List 优于 数组
 * 数组是在运行时知道和强化元素类型的
 *
 * 而范型是在编译时强化数据类型，运行时擦除数据类型的
 * 所以数据和范型不能一起使用
 *
 * 数组 是具体化的
 * 参数化类型范型 是非具体化的
 * 无限通配符的是 可具体化的参数化类型范型
 *
 * Created by mamingchao on 2021/1/3.
 */
public class Test<T> {
    static List list = new ArrayList<>();
    static List<?> list1 = new ArrayList<>();

    public static void main(String[] args) {
        list.add(1234);
        list.add("eropjodn");
        list.add(new Song());

        //这里会报错，尽管错误提示 不能让我们满意，但是编译器已经做了最大的努力
        // 不能将除了null之外的任何元素 add到list1中
        list1.add(null);
//        list1.add(1234);
//        list1.add(String.valueOf("eropjodn"));
//        list1.add(new Song());

        //不要使用 原生类型，有几个例外
        //1、类文字，xxxx.class，要使用原生态，使用 范型报错

        Class a = int.class;
        Class b = List.class;
        Class c = String[].class;

        //这个是错误的
//        Class c = List<String>.class;

        //2、instanceOf 范型在运行时 类型会擦除，所以不能用 instanceOf，只能 原生态可以使用
        if (list instanceof List) {
            System.out.println(true);
        }

        //这里用 List<?> 和 使用原生态List 没区别，没有任何影响
        if (list1 instanceof List<?>) {
            System.out.println(true);
        }




        //报 generic array creation 错误。数组和范型不能一起用
        //范型在运行时类型擦除，所以stringList 类型是List[],integerList是 List
        //但是倒数第二句的时候，把Integer类型的列表放到String 类型列表数组里，肯定报 ClassCastException
        //所以，如果用参数化类型范型数组，前面不报错，后面运行的时候也会报错；所以现在不让范型数组一起用，直接在第一句
        //就提示 generic array creation 错误
        // 技术上讲，E List<E> List<String> 都是不可具体化的类型
//        List<String>[] stringList = new List<String>[1];
//        List<Integer> integerList = Arrays.asList(42);
//
//        Object[] objects = stringList;
//        objects[0] = integerList;
//        String s = stringList[0].get(0);

        //这个虽然不常用，但是不会报错，因为 无限制通配符是可具体化的
//        List<?>[] temps = new List<?>[10];

    }


    //这两个 方法 是等效的，只是 无限通配符 不能 存放任何非null的元素，会报错
    public static <E> void swap(List<E> list, int i, int j) {
        list.set(i, list.set(j, list.get(i)));
    }

    public static void swap1(List<?> list, int i, int j) {
        swap2(list, i ,j);
    }

    //编写一个 辅助方法来捕捉通配符，这个跟上面的 范型方法是一样的，就是 访问等级编程 private的了
    private static <E> void swap2(List<E> list, int i, int j) {
        list.set(i, list.set(j, list.get(i)));
    }



}
